package cos

import (
	"context"
	"fmt"
	"gpt-api/framework/log"
	"gpt-api/pkg/util"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"

	// 错误处理 可自行配置
	// 公共变量 可自行配置
	"time"

	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"github.com/tencentyun/cos-go-sdk-v5"
)

// 保存文件
func saveUploadedFile(file *multipart.FileHeader, newSavePath string) (r bool, saveFilePath string) {
	//COS客户端连接
	cosUrl, _ := url.Parse(viper.GetString("cos.CosUrl"))
	secretId := viper.GetString("cos.SecretID")
	secretKey := viper.GetString("cos.SecretKey")
	b := &cos.BaseURL{BucketURL: cosUrl}
	client := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  secretId,
			SecretKey: secretKey,
		},
	})

	//  保存文件，原始文件名进行全局唯一编码加密、md5 加密，保证在后台存储不重复
	var saveErr error
	if sequence := time.Now().UnixNano(); sequence > 0 {
		saveFileName := fmt.Sprintf("%d%s", sequence, file.Filename)
		saveFileName = util.Md5(saveFileName) + path.Ext(saveFileName)
		saveFilePath := newSavePath + saveFileName
		// 3.通过文件流上传对象
		fd, err := file.Open()
		if err != nil {
			return false, ""
		}
		defer fd.Close()

		_, saveErr = client.Object.Put(context.Background(), saveFilePath, fd, nil)

		if saveErr == nil {
			//  上传成功,返回资源的相对路径，这里请根据实际返回绝对路径或者相对路径
			return true, saveFilePath
		} else {
			//saveErr = errors.New(my_errors.ErrorsCosUploadFail)
			// 保存错误日志
			log.Info("上传文件失败:" + saveErr.Error())
		}
	} else {
		//saveErr = errors.New(my_errors.ErrorsSnowflakeGetIdFail)
		// 保存错误日志
		log.Info("获取当前时间戳失败")
	}
	return false, ""
}

func saveLocalFile(file string, newSavePath string) (r bool, saveFilePath string) {
	//COS客户端连接
	cosUrl, _ := url.Parse(viper.GetString("cos.CosUrl"))
	secretId := viper.GetString("cos.SecretID")
	secretKey := viper.GetString("cos.SecretKey")
	b := &cos.BaseURL{BucketURL: cosUrl}
	client := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  secretId,
			SecretKey: secretKey,
		},
	})

	//  保存文件，原始文件名进行全局唯一编码加密、md5 加密，保证在后台存储不重复
	var saveErr error
	if sequence := time.Now().UnixNano(); sequence > 0 {
		saveFileName := fmt.Sprintf("%d%s", sequence, file)
		saveFileName = util.Md5(saveFileName) + path.Ext(saveFileName)
		saveFilePath := newSavePath + saveFileName
		// 3.通过文件流上传对象
		fd, err := os.Open(file)
		if err != nil {
			return false, ""
		}
		defer fd.Close()

		_, saveErr = client.Object.Put(context.Background(), saveFilePath, fd, nil)

		if saveErr == nil {
			//  上传成功,返回资源的相对路径，这里请根据实际返回绝对路径或者相对路径
			return true, saveFilePath
		}
	} else {
		//saveErr = errors.New(my_errors.ErrorsSnowflakeGetIdFail)
		// 保存错误日志
		log.Info("获取当前时间戳失败")
	}
	return false, ""
}

func generateYearMonthPath(savePathPre string) string {
	curYearMonth := time.Now().Format("2006/01")
	newSavePathPre := savePathPre + curYearMonth
	return newSavePathPre + "/"
}

// 单文件上传
func Upload(ctx *gin.Context, savePath string) (r bool, finnalSavePath interface{}) {
	// 对象键（Key）是对象在存储桶中的唯一标识。
	newSavePath := generateYearMonthPath(savePath)

	//  1.获取上传的文件名(参数验证器已经验证完成了第一步错误，这里简化)
	filefield := viper.GetString("FileUploadSetting.UploadFileField")
	file, _ := ctx.FormFile(filefield) //  file 是一个文件结构体（文件对象）
	if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {

		// 上传成功,返回资源的相对路径，这里请根据实际返回绝对路径或者相对路径
		finnalSavePath = gin.H{
			"path": saveFilePath,
		}
		return true, finnalSavePath
	}

	return false, nil
}

func UploadImg(ctx *gin.Context, savePath string) (r bool, finnalSavePath interface{}) {
	// 对象键（Key）是对象在存储桶中的唯一标识。
	newSavePath := generateYearMonthPath(savePath)

	//  1.获取上传的文件名(参数验证器已经验证完成了第一步错误，这里简化)
	//filefield := viper.GetString("FileUploadSetting.UploadFileField")
	file, _ := ctx.FormFile("image") //  file 是一个文件结构体（文件对象）
	if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {

		// 上传成功,返回资源的相对路径，这里请根据实际返回绝对路径或者相对路径
		finnalSavePath = gin.H{
			"path": saveFilePath,
		}
		return true, finnalSavePath
	}

	return false, nil
}

// 多文件上传
func MultUpload(ctx *gin.Context, savePath string) (r bool, multFinnalSavePath interface{}) {

	// 对象键（Key）是对象在存储桶中的唯一标识。
	newSavePath := generateYearMonthPath(savePath)
	//获取到所有的文件
	form, _ := ctx.MultipartForm()
	//获取到所有的文件数组
	files := form.File[viper.GetString("FileUploadSetting.UploadFileField")]
	var saveFilePaths []string
	//遍历数组进行处理
	for _, file := range files {
		//进行文件保存
		if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {
			saveFilePaths = append(saveFilePaths, saveFilePath)
		}
	}
	// 上传成功,返回资源的相对路径，这里请根据实际返回绝对路径或者相对路径
	multFinnalSavePath = gin.H{
		"paths": saveFilePaths,
	}
	return true, multFinnalSavePath

}

func UploadLocalFile(localFile string, savePath string) (r bool, finnalSavePath string) {
	newSavePath := generateYearMonthPath(savePath)

	if r, saveFilePath := saveLocalFile(localFile, newSavePath); r == true {
		// 上传成功,返回资源的相对路径，这里请根据实际返回绝对路径或者相对路径
		// finnalSavePath = gin.H{
		// 	"path": saveFilePath,
		// }
		return true, saveFilePath
	}
	return false, ""
}

func GetCosFile(file string) (string, error) {
	//COS客户端连接
	cosUrl, _ := url.Parse(viper.GetString("cos.CosUrl"))
	secretId := viper.GetString("cos.SecretID")
	secretKey := viper.GetString("cos.SecretKey")
	b := &cos.BaseURL{BucketURL: cosUrl}
	c := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  secretId,
			SecretKey: secretKey,
		},
	})

	// 1.通过响应体获取对象
	// name := "/yq/picture/2024/09/3c92ffec85fbe915e3578f616e920799.png"
	// resp, err := c.Object.Get(context.Background(), name, nil)
	// if err != nil {
	// 	panic(err)
	// }

	// io.ReadAll(resp.Body)
	// resp.Body.Close()
	// 解析/yq/picture/2024/09/3c92ffec85fbe915e3578f616e920799.png 获取到文件名
	_, name := filepath.Split(file)

	// 2.获取对象到本地文件
	_, err := c.Object.GetToFile(context.Background(), file, viper.GetString("did.tmpPath")+name, nil)
	if err != nil {
		return "", err
	}
	return viper.GetString("did.tmpPath") + name, nil
}
